package cn.stalk.compare;

import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map.Entry;

public class DataWrapper<T> {

    protected LinkedHashMap<String, Object> keys = new LinkedHashMap<>();
    protected LinkedHashMap<String, DataAccessor<T, Object>> keyDataAccessorMap;
    protected T value;

    protected DataWrapper(T value, LinkedHashMap<String, DataAccessor<T, Object>> keyDataAccessorMap) {
        this.value = value;
        this.keyDataAccessorMap = keyDataAccessorMap;
        for (DataAccessor<T, Object> keyDataAccessor : keyDataAccessorMap.values()) {
            keys.put(keyDataAccessor.getName(), keyDataAccessor.getValue(value));
        }
    }

    protected DataWrapper(T value) {
        this.value = value;
        keys.put(null, value);
    }

    protected static <T> DataWrapper<T> empty() {
        return new DataWrapper<T>(null);
    }

    /**
     * 唯一标识，实际是Map<DataAccessor<T, Object>, Object> keys
     */
    public Object getId() {
        return keys;
    }

    public T getValue() {
        return value;
    }

    public boolean isNull() {
        return null == value;
    }

    /**
     * 比较id，o不为null
     */
    public int idCompare(DataWrapper<T> o) {
        if (isNull() || o.isNull() || null == keyDataAccessorMap || keyDataAccessorMap != o.keyDataAccessorMap) {
            throw new RuntimeException("Not support.");
        }
        Iterator<Entry<String, Object>> iter = keys.entrySet().iterator();
        Iterator<Entry<String, Object>> oIter = o.keys.entrySet().iterator();
        // 两者key数量一致
        for (; iter.hasNext() && oIter.hasNext(); ) {
            Entry<String, Object> entry = iter.next();
            Entry<String, Object> oEntry = oIter.next();
            if (null != entry.getValue() && null != oEntry.getValue()) {
                if ((entry.getValue() instanceof Comparable) && oEntry.getValue() instanceof Comparable) {
                    int rs = ((Comparable) entry.getValue()).compareTo(oEntry.getValue());
                    if (rs == 0) {
                        continue;
                    }
                    return rs;
                }
                if (entry.getValue().equals(oEntry.getValue())) {
                    continue;
                }
                throw new RuntimeException("Can not compare:" + entry.getKey());
            }
            if (null == entry.getValue() && null == oEntry.getValue()) {
                continue;
            }
            boolean nullsLast = keyDataAccessorMap.get(entry.getKey()).isNullsLast();
            if (null == entry.getValue()) {
                return nullsLast ? 1 : -1;
            } else {
                return nullsLast ? -1 : 1;
            }
        }
        return 0;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof DataWrapper) {
            return keys.equals(((DataWrapper<?>) obj).keys);
        }
        return false;
    }

    @Override
    public int hashCode() {
        return keys.hashCode();
    }

    @Override
    public String toString() {
        StringBuilder buf = new StringBuilder();
        for (Entry<String, Object> entry : keys.entrySet()) {
            if (buf.length() > 0) {
                buf.append(",");
            }
            buf.append(entry.getKey()).append("=").append(entry.getValue());
        }
        return buf.insert(0, "{").append("}").toString();
    }

}
